// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。chuang jian defg

// 
// 对服务器的传入请求应创建上下文，对服务器的传出
// 调用应接受上下文。函数链
// 它们之间的调用必须传播上下文，可以选择将
// 替换为使用WithCancel、WithDeadline、
// WithTimeout或WithValue创建的派生上下文。当一个上下文被取消时，从它派生的所有
// 上下文也被取消。
// 
// WithCancel、WithDeadline和WithTimeout函数获取
// 上下文（父级）并返回派生上下文（子级）和
// CancelFunc。调用CancelFunc将取消子项及其
// 子项，删除父项对子项的引用，并停止
// 任何相关计时器。未能调用CancelFunc会泄漏
// 子级及其子级，直到父级被取消或计时器
// 触发。go vet工具检查CancelFuncs是否用于所有
// 控制流路径。
// 
// 使用上下文的程序应遵循以下规则，以保持接口
// 在包之间的一致性，并启用静态分析工具来检查上下文
// 传播：
// 
// 不要在结构类型中存储上下文；相反，将上下文
// 显式传递给每个需要它的函数。上下文应该是第一个
// 参数，通常命名为ctx:
// 
// func DoSomething（ctx Context.Context，arg arg）error{
// ……use ctx…
// }
// 
// 即使函数允许，也不要传递零上下文。传递上下文。TODO 
// 如果您不确定要使用哪个上下文。
// 
// 仅对传输进程的请求范围数据和
// API使用上下文值，不用于向函数传递可选参数。
// 
// 相同的上下文可以传递给在不同goroutine中运行的函数；
// 多个Goroutine同时使用上下文是安全的。
// 参见https:
// 上下文的服务器代码。
package context

import (
	"errors"
	"internal/reflectlite"
	"sync"
	"sync/atomic"
	"time"
)

// 上下文跨API边界携带截止日期、取消信号和其他值。
// 
// 多个Goroutine可以同时调用上下文的方法。
type Context interface {
	// Deadline返回代表此上下文完成的工作应被取消的时间。如果未设置截止日期
	// 则Deadline返回ok==false。连续调用Deadline返回相同的结果。
	Deadline() (deadline time.Time, ok bool)

	// 当代表此
	// 上下文完成的工作应被取消时，返回一个关闭的通道。如果此上下文可以
	// 永远不会被取消，则Done可能返回nil。连续调用Done返回相同的值。
	// 完成通道的关闭可能会异步进行，
	// 在cancel函数返回后。
	// 
	// WithCancel在调用cancel时安排关闭Done；
	// 有截止日期安排在截止日期
	// 到期时关闭；WithTimeout安排在超时
	// 结束时关闭Done。
	// 
	// Done提供用于select语句：
	// 
	// 
	// 
	// func Stream（ctx context.context，out chan<-Value）错误{
	// {
	// 返回错误
	// /}
	// 选择{
	// case<-ctx.Done（）：
	// 返回ctx.err（）
	// case out<-v:
	// /}
	Done() <-chan struct{}

	// 如果尚未关闭Done，Err返回nil。
	// 如果关闭了“完成”，Err将返回一个非零错误，解释原因：
	// 如果上下文被取消，则取消
	// 如果上下文的截止日期已过，则超出死线。
	// Err返回非nil错误后，对Err的连续调用将返回相同的错误。
	Err() error

	// Value返回与key的上下文相关联的值，如果没有与key相关联的值，则返回nil 
	// 值。使用
	// 连续调用Value，同一个键返回相同的结果。
	// 
	// 仅对传输
	// 进程和API边界的请求范围数据使用上下文值，而不是将可选参数传递给
	// 函数。
	// 
	// 键标识上下文中的特定值。希望
	// 在上下文中存储值的函数通常在全局
	// 变量中分配一个键，然后将该键用作上下文的参数。WithValue和
	// 上下文。价值密钥可以是支持相等的任何类型；
	// 包应将密钥定义为未报告的类型，以避免
	// 冲突。
	// 
	// 定义上下文键的包应该为使用该键存储的值提供类型安全的访问器
	// 
	// 
	// 
	// 包用户
	// 
	// 导入“上下文”
	// type user结构{…}
	// 
	// 
	// 
	// 。Context{
	// 返回Context.WithValue（ctx，userKey，u）
	// 
	// 
	// func FromContext（ctx Context.Context）（*User，bool）{
	// u，ok:=ctx.Value（userKey）。（*User）
	// 返回u，ok 
	Value(key any) any
}

var Canceled = errors.New("context canceled")

// deadlineextered是上下文返回的错误。当上下文的
// 截止日期过去时出错。
var DeadlineExceeded error = deadlineExceededError{}

type deadlineExceededError struct{}

func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
func (deadlineExceededError) Timeout() bool   { return true }
func (deadlineExceededError) Temporary() bool { return true }

// emptyCtx永远不会被取消，没有值，也没有截止日期。它不是
// struct{}，因为这种类型的变量必须有不同的地址。
type emptyCtx int

func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
	return
}

func (*emptyCtx) Done() <-chan struct{} {
	return nil
}

func (*emptyCtx) Err() error {
	return nil
}

func (*emptyCtx) Value(key any) any {
	return nil
}

func (e *emptyCtx) String() string {
	switch e {
	case background:
		return "context.Background"
	case todo:
		return "context.TODO"
	}
	return "unknown empty Context"
}

var (
	background = new(emptyCtx)
	todo       = new(emptyCtx)
)

// 后台返回非零的空上下文。它从未被取消，没有
// 值，也没有截止日期。它通常由主函数
// 初始化和测试使用，并作为传入
// 请求的顶级上下文。
func Background() Context {
	return background
}

// TODO返回一个非零的空上下文。代码应该使用上下文。TODO when 
// 不清楚要使用哪个上下文，或者它还不可用（因为
// 周边函数还没有扩展到接受上下文
// 参数）。
func TODO() Context {
	return todo
}

// CancelFunc告诉操作放弃其工作。
// 取消函数不会等待工作停止。
// 一个CancelFunc可以被多个goroutine同时调用。
// 在第一次调用之后，对CancelFunc的后续调用不会执行任何操作。
type CancelFunc func()

// WithCancel返回带有新完成通道的父级副本。返回的
// 当返回的cancel函数调用
// 上下文的完成通道关闭。
// 或当父上下文的完成通道关闭时（以先发生的为准），返回的
// 
// 取消此上下文将释放与其关联的资源，因此代码应该在此上下文中运行的操作完成后立即调用cancel。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	c := newCancelCtx(parent)
	propagateCancel(parent, &c)
	return &c, func() { c.cancel(true, Canceled) }
}

// newCancelCtx返回一个初始化的cancelCtx。
func newCancelCtx(parent Context) cancelCtx {
	return cancelCtx{Context: parent}
}

// goroutines统计曾经创建的goroutines的数量；用于测试。
var goroutines int32

// CANCEL安排在父项为空时取消子项。
func propagateCancel(parent Context, child canceler) {
	done := parent.Done()
	if done == nil {
		return // 父项从未被取消
	}

	select {
	case <-done:
		// 父项已被取消
		child.cancel(false, parent.Err())
		return
	default:
	}

	if p, ok := parentCancelCtx(parent); ok {
		p.mu.Lock()
		if p.err != nil {
			// 父项已被取消
			child.cancel(false, p.err)
		} else {
			if p.children == nil {
				p.children = make(map[canceler]struct{})
			}
			p.children[child] = struct{}{}
		}
		p.mu.Unlock()
	} else {
		atomic.AddInt32(&goroutines, +1)
		go func() {
			select {
			case <-parent.Done():
				child.cancel(false, parent.Err())
			case <-child.Done():
			}
		}()
	}
}

// &cancelCtxKey是cancelCtx返回自身的密钥。
var cancelCtxKey int

// parentCancelCtx返回父级的基础*cancelCtx。
// 它通过查找父对象来实现这一点。值（&cancelCtxKey）来查找
// 最里面的封闭*cancelCtx，然后检查
// 是否为父级。Done（）与*cancelCtx匹配。（如果没有，则*cancelCtx 
// 已包装在提供
// 不同的完成通道，在这种情况下，我们不应该绕过它。）
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
	done := parent.Done()
	if done == closedchan || done == nil {
		return nil, false
	}
	p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
	if !ok {
		return nil, false
	}
	pdone, _ := p.done.Load().(chan struct{})
	if pdone != done {
		return nil, false
	}
	return p, true
}

// removeChild从其父级删除上下文。
func removeChild(parent Context, child canceler) {
	p, ok := parentCancelCtx(parent)
	if !ok {
		return
	}
	p.mu.Lock()
	if p.children != nil {
		delete(p.children, child)
	}
	p.mu.Unlock()
}

// 取消器是可以直接取消的上下文类型。
// 实现是*cancelCtx和*timerCtx。
type canceler interface {
	cancel(removeFromParent bool, err error)
	Done() <-chan struct{}
}

// closedchan是一个可重复使用的封闭通道。
var closedchan = make(chan struct{})

func init() {
	close(closedchan)
}

// 可以取消取消CTX。取消时，它还会取消实现取消器的所有子项
// 。
type cancelCtx struct {
	Context

	mu       sync.Mutex            // 保护chan struct{}的以下字段
	done     atomic.Value          // 惰性创建，通过第一次取消调用关闭
	children map[canceler]struct{} // 通过第一次取消调用设置为零
	err      error                 // 通过第一次取消调用
}

func (c *cancelCtx) Value(key any) any {
	if key == &cancelCtxKey {
		return c
	}
	return value(c.Context, key)
}

func (c *cancelCtx) Done() <-chan struct{} {
	d := c.done.Load()
	if d != nil {
		return d.(chan struct{})
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	d = c.done.Load()
	if d == nil {
		d = make(chan struct{})
		c.done.Store(d)
	}
	return d.(chan struct{})
}

func (c *cancelCtx) Err() error {
	c.mu.Lock()
	err := c.err
	c.mu.Unlock()
	return err
}

type stringer interface {
	String() string
}

func contextName(c Context) string {
	if s, ok := c.(stringer); ok {
		return s.String()
	}
	return reflectlite.TypeOf(c).String()
}

func (c *cancelCtx) String() string {
	return contextName(c.Context) + ".WithCancel"
}

// 取消关闭c。完成后，取消c的每个子项，如果
// removeFromParent为真，从其父对象的子对象中移除c。
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
	if err == nil {
		panic("context: internal error: missing cancel error")
	}
	c.mu.Lock()
	if c.err != nil {
		c.mu.Unlock()
		return // 已取消
	}
	c.err = err
	d, _ := c.done.Load().(chan struct{})
	if d == nil {
		c.done.Store(closedchan)
	} else {
		close(d)
	}
	for child := range c.children {
		// 注意：在持有父锁的同时获取子锁。
		child.cancel(false, err)
	}
	c.children = nil
	c.mu.Unlock()

	if removeFromParent {
		removeChild(c.Context, c)
	}
}

// WithDeadline返回父上下文的副本，其截止日期调整后的
// 不晚于d。如果父上下文的截止日期早于d，则
// WithDeadline（parent，d）在语义上等同于parent。当截止日期到期、调用返回的
// 上下文的完成通道关闭。
// 取消函数或父上下文的完成通道
// 关闭时（以先发生的为准），返回的
// 
// 取消此上下文将释放与其关联的资源，因此代码应该在此上下文中运行的操作完成后立即调用cancel。
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	if cur, ok := parent.Deadline(); ok && cur.Before(d) {
		// 当前的截止日期已经比新的截止日期早。
		return WithCancel(parent)
	}
	c := &timerCtx{
		cancelCtx: newCancelCtx(parent),
		deadline:  d,
	}
	propagateCancel(parent, c)
	dur := time.Until(d)
	if dur <= 0 {
		c.cancel(true, DeadlineExceeded) // 截止日期已过
		return c, func() { c.cancel(false, Canceled) }
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err == nil {
		c.timer = time.AfterFunc(dur, func() {
			c.cancel(true, DeadlineExceeded)
		})
	}
	return c, func() { c.cancel(true, Canceled) }
}

// timerCtx带有计时器和截止日期。它在
// implement Done and Err中嵌入了一个cancelCtx。它通过停止计时器来实现取消，然后
// 委托给cancelCtx。取消
type timerCtx struct {
	cancelCtx
	timer *time.Timer // 在cancelCtx下。穆。

	deadline time.Time
}

func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
	return c.deadline, true
}

func (c *timerCtx) String() string {
	return contextName(c.cancelCtx.Context) + ".WithDeadline(" +
		c.deadline.String() + " [" +
		time.Until(c.deadline).String() + "])"
}

func (c *timerCtx) cancel(removeFromParent bool, err error) {
	c.cancelCtx.cancel(false, err)
	if removeFromParent {
		// 从其父级cancelCtx的子级删除此时间RCTX。
		removeChild(c.cancelCtx.Context, c)
	}
	c.mu.Lock()
	if c.timer != nil {
		c.timer.Stop()
		c.timer = nil
	}
	c.mu.Unlock()
}

// WithTimeout返回WithDeadline（父级，time.Now（）。添加（超时）。
// 
// 取消此上下文将释放与其关联的资源，因此，代码应该在这个上下文中运行的操作完成后立即调用cancel:
// 
// func slowOperationWithTimeout（ctx Context.Context）（Result，error）{
// ctx，cancel:=Context.WithTimeout（ctx，100*time.毫秒）
// 返回慢操作（ctx）
// }
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	return WithDeadline(parent, time.Now().Add(timeout))
}

// WithValue返回父级的副本，其中与键关联的值为
// val.
// 
// 仅对传输进程和
// API，不用于向函数传递可选参数。
// 
// 提供的密钥必须具有可比性，且不应为
// 字符串或任何其他内置类型，以避免使用上下文的
// 包之间发生冲突。WithValue的用户应该为密钥定义自己的
// 类型。为了避免在分配给
// 接口{}时进行分配，上下文键通常具有具体类型
// struct{}。或者，导出的上下文键变量的静态
// 类型应该是指针或接口。
func WithValue(parent Context, key, val any) Context {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	if key == nil {
		panic("nil key")
	}
	if !reflectlite.TypeOf(key).Comparable() {
		panic("key is not comparable")
	}
	return &valueCtx{parent, key, val}
}

// valueCtx携带一个键值对。它实现该键的值，并且
// 将所有其他调用委托给嵌入式上下文。
type valueCtx struct {
	Context
	key, val any
}

// stringify尝试在不使用fmt的情况下对v进行一点stringify，因为我们不需要依赖unicode表的上下文。这仅由
// /*valueCtx使用。字符串（）。
func stringify(v any) string {
	switch s := v.(type) {
	case stringer:
		return s.String()
	case string:
		return s
	}
	return "<not Stringer>"
}

func (c *valueCtx) String() string {
	return contextName(c.Context) + ".WithValue(type " +
		reflectlite.TypeOf(c.key).String() +
		", val " + stringify(c.val) + ")"
}

func (c *valueCtx) Value(key any) any {
	if c.key == key {
		return c.val
	}
	return value(c.Context, key)
}

func value(c Context, key any) any {
	for {
		switch ctx := c.(type) {
		case *valueCtx:
			if key == ctx.key {
				return ctx.val
			}
			c = ctx.Context
		case *cancelCtx:
			if key == &cancelCtxKey {
				return c
			}
			c = ctx.Context
		case *timerCtx:
			if key == &cancelCtxKey {
				return &ctx.cancelCtx
			}
			c = ctx.Context
		case *emptyCtx:
			return nil
		default:
			return c.Value(key)
		}
	}
}
